import { _decorator, Component, Node, Tween } from 'cc';
import BaseComp from '../../common/BaseComp';
import { Sprite } from 'cc';
import { UITransform } from 'cc';
import { Vec3 } from 'cc';
import { director } from 'cc';
import { eliminateGameManager } from './EliminateGameManager';
import { geometry } from 'cc';
import { PhysicsSystem } from 'cc';
import { RigidBody } from 'cc';
import { tween } from 'cc';
import { Collider } from 'cc';
import { v3 } from 'cc';
import { Quat } from 'cc';
import { view } from 'cc';
import { JsonAsset } from 'cc';
import { Size } from 'cc';
import { screen } from 'cc';
import { createRandom, findNCommon, findThreeCommon, groupSameElements2, Queue } from '../../common/util';
import { ParticleSystem2D } from 'cc';
import { eliminateConsts } from './EliminateConst';
import { ProgressBar } from 'cc';
import { Label } from 'cc';
import { EventTouch } from 'cc';
import { BlockInputEvents } from 'cc';
import { clamp } from 'cc';
import { eventManager } from '../../common/eventManager';
import { Button } from 'cc';
import { PhyGroup } from './EliminateSlot';
import { EliminateToy } from './EliminateToy';
import { GameOverReason } from './EliminateGame';
import JsbUtils, { jsbUtils } from '../../common/JsbUtil';
const { ccclass, property } = _decorator;

@ccclass('EliminateMatch3Logic')
export class EliminateMatch3Logic extends BaseComp {

    @property(JsonAsset)
    allToyRotateJson: JsonAsset = null;

    clear2: UITransform = null;

    private tools: Sprite = null;
    private toolBg: Sprite = null;
    private freeze: Sprite = null;

    private boxContainer: Sprite = null;


    private total: number = 7;

    /** 格子填充情况 */
    private modelView: Node[] = [];
    /** 当前填充的格子索引 */
    private curBox: number = 0;

    private _scale: number = 0.6;

    private windPart: UITransform = null;
    private icePart: UITransform = null;

    private continuousProgress: ProgressBar = null;
    private continuousLabel: Label = null;

    private deleteQueue: Queue<Array<Node>> = new Queue();

    /** 每一个格子对应的世界坐标 */
    private slotIndexPostionMap: Map<number, Vec3> = new Map();

    /** 是否正在消除 */
    private _isEliminating: boolean = false;

    __preload(): void {
        this.openFilter = true;
        super.__preload();
    }

    public updateTimesLabel(times: number | string) {
        this.continuousLabel.string = `x${times.toString()}`;
    }

    protected onLoad(): void {
        this.continuousLabel.string = "x1";
        this.continuousProgress.progress = 0;
    }

    start() {
        console.log("boxContainer is ", this.boxContainer);
    }

    onEnable(): void {
        // this.node.on(Node.EventType.TOUCH_END, this.tapTool, this);
        eventManager.on("freeze_start", this.freezeStartEvent, this);
        eventManager.on("freeze_over", this.freezeEndEvent, this);
    }

    private freezeStartEvent() {
        // 置灰冻结按钮
        const freezeButton = this.freeze.getComponent(Button);
        this.freeze.grayscale = true;
        freezeButton.interactable = false;
    }

    private freezeEndEvent() {
        // 冻结按钮可以点击了
        this.freeze.getComponent(Button).interactable = true;
        this.freeze.grayscale = false;
    }

    onDisable(): void {
        eventManager.remove("freeze_start", this.freezeStartEvent);
        eventManager.remove("freeze_over", this.freezeEndEvent);
    }

    private _prepareAllSlotWorldPos() {
        if (this.slotIndexPostionMap.size > 0) return;
        const d3Camera = eliminateGameManager.uiManager.camera;
        for (let i = 0; i < eliminateConsts.eliminate_slot; i++) {
            // 逐个的进行射线检测
            let pos = this.boxContainer.node.children[i].getWorldPosition();
            let ray = new geometry.Ray();

            const designSize = view.getDesignResolutionSize();
            let canvasSize = new Size(screen.windowSize.width * screen.devicePixelRatio, screen.windowSize.height * screen.devicePixelRatio);

            let wratio = canvasSize.width / designSize.width;
            wratio = view.getVisibleSizeInPixel().width / designSize.width;

            pos.x *= wratio;
            pos.y *= wratio;
            pos.y -= 5 * wratio;

            d3Camera.screenPointToRay(pos.x, pos.y, ray);

            const mask = 1 << 2;
            const maxDistance = 1000000;

            const hasCast = PhysicsSystem.instance.raycastClosest(ray, mask, maxDistance);
            const res = PhysicsSystem.instance.raycastClosestResult;
            const hitPoint = res.hitPoint.clone();
            hitPoint.y = 100;

            if (!this.slotIndexPostionMap.has(i)) {
                this.slotIndexPostionMap.set(i, hitPoint);
            }
        }
    }

    eliminateCheck(node: Node) {
        // 只检测一次射线
        this._prepareAllSlotWorldPos();

        const jsonData = this.allToyRotateJson.json;
        let index = this.modelView.length;
        if (index >= eliminateConsts.eliminate_slot) return;

        if (this.modelView.indexOf(node) < 0) {
            this.modelView.push(node);
        }

        // 先确定插入位置i,同时挪动插入位置后的元素
        const { result, indexChanges, insertPos } = groupSameElements2(this.modelView, node, 'tag');

        const toyComp = node.getComponent(EliminateToy);
        if (insertPos != -1) {
            toyComp.slotIndex = insertPos;
        } else {
            toyComp.slotIndex = index;
        }
        const worldPos = this.slotIndexPostionMap.get(toyComp.slotIndex);
        console.log("worldPos is ", worldPos);

        // 索引改变的元素移动
        if (indexChanges.length > 0) {
            for (let i = 0; i < indexChanges.length; i++) {
                let moveStr = indexChanges[i] as string;
                const splitRes = moveStr.split('->');
                let startIndex = +splitRes[0];
                let endIndex = +splitRes[1];
                this._moveNodeToTargetIndex(endIndex, this.modelView[startIndex], 0.1);
            }
        }

        let rb = node.getComponent(RigidBody);
        const collider = node.getComponent(Collider);
        collider.enabled = false;

        rb.setLinearVelocity(v3(0, 0, 0));
        rb.setAngularVelocity(v3(0, 0, 0));
        rb.useGravity = false;
        rb.enabled = false;

        const targetScale = node.scale.clone().multiplyScalar(this._scale);

        let targetQuat = new Quat();
        const tag = node['tag'];

        const rotateX = jsonData[tag] ? jsonData[tag].rotateX : 0;
        const rotateY = jsonData[tag] ? jsonData[tag].rotateY : 0;
        const rotateZ = jsonData[tag] ? jsonData[tag].rotateZ : 0;

        Quat.fromEuler(targetQuat, rotateX, rotateY, rotateZ);

        this.modelView = result;
        tween(rb.node).to(0.5, { position: worldPos, scale: targetScale, rotation: targetQuat }).call((node: Node) => {
            // 飞到了slot里面
            node['inSlot'] = true;
            let canClear = this._consecutiveEliminate();

            if (!canClear && this.modelView.length >= eliminateConsts.eliminate_slot) {
                eliminateGameManager.game.overReason = GameOverReason.NOT_COMPLETE_LEVEL;
                // 游戏结束
                eliminateGameManager.uiManager.popPause();
            }
        }).start();
    }

    private async _moveNodeToTargetIndex(targetIndex: number, node: Node, time: number = 0.1) {
        const targetPos = this.slotIndexPostionMap.get(targetIndex);
        // @ts-ignore
        console.log(`${node._id}-${node.name} -> 移动到 ${targetIndex}位置上`, targetPos);
        const toyComp = node.getComponent(EliminateToy);
        const jsonData = this.allToyRotateJson.json;

        Tween.stopAllByTarget(node);
        let targetQuat = new Quat();
        const tag = node['tag']
        const rotateX = jsonData[tag] ? jsonData[tag].rotateX : 0;
        const rotateY = jsonData[tag] ? jsonData[tag].rotateY : 0;
        const rotateZ = jsonData[tag] ? jsonData[tag].rotateZ : 0;

        const targetScale = toyComp.originScale.clone().multiplyScalar(this._scale);

        Quat.fromEuler(targetQuat, rotateX, rotateY, rotateZ);

        return new Promise((resolve, reject) => {
            tween(node).to(time, { position: targetPos, rotation: targetQuat, scale: targetScale }).call(() => {
                // @ts-ignore
                console.log(`${node._id}-${node.name} move to ${targetIndex} location over`);
                node.setPosition(targetPos);
                node['inSlot'] = true;
                console.log("node pos is ", node.position);
                resolve(null);
            }).start();
        });
    }

    /**
     * 严格的连续消除，并且重新排布槽子里面物体的顺序
     */
    private _consecutiveEliminate() {
        // const inSlotNodes = this.modelView.filter(item => item['inSlot']);
        const fineRes = findNCommon<Node>(this.modelView, 'tag', eliminateConsts.eliminateLimit);
        const deleteIndexs = fineRes;

        if (deleteIndexs.length >= eliminateConsts.eliminateLimit) {
            const deleteNodes = [];
            for (let i = 0; i < this.modelView.length; i++) {
                if (deleteIndexs.indexOf(i) >= 0) {
                    deleteNodes.push(this.modelView[i]);
                }
            }
            const isAllInSlot = deleteNodes.every(item => item['inSlot']);
            console.warn("消除节点够了，但是有些节点的标志位不是 inSlot");

            if (isAllInSlot) {
                deleteNodes.forEach(item => item['clear'] = true);
                this.deleteQueue.push(deleteNodes);
                // 更新视图数据
                this.modelView.splice(deleteIndexs[0], eliminateConsts.eliminateLimit);
                // 执行消除动作
                this._execEliminate().then(() => {
                    // 有消除行为重新排布所有未消除的元素
                    this._resetSlotsObject().then(() => {
                        this._consecutiveEliminate();
                    })
                })

                return true;
            }
        }
        return false;
    }

    /** 执行真正的消除逻辑 从队列里面弹出待消除数组 */
    private async _execEliminate() {
        if (!this.deleteQueue.isEmpty()) {
            if (this._isEliminating) return;
            JsbUtils.callVibration("d");
            if (!this._isEliminating) {
                this._isEliminating = true;
            }

            let items = this.deleteQueue.pop();
            await this._deleteAction(items);
        }
    }

    private async _resetSlotsObject() {
        console.log("modelView length is ", this.modelView.length);
        for (let i = 0; i < this.modelView.length; i++) {
            const item = this.modelView[i];
            if (i == this.modelView.length - 1) {
                await this._moveNodeToTargetIndex(i, item, 0.1);
            } else {
                this._moveNodeToTargetIndex(i, item, 0.1);
            }
        }
    }

    /**
     * 执行消除动画，删除节点
     * @param  {Node[]} deleteNodes
     */
    private async _deleteAction(deleteNodes: Node[]) {
        // 开始加分进度条倒计
        const score = eliminateGameManager.game.addScore();

        const center = deleteNodes[1].getPosition();
        let centerWorld = this.boxContainer.getComponent(UITransform).convertToWorldSpaceAR(center);
        let localPos = this.node.getComponent(UITransform).convertToNodeSpaceAR(centerWorld);

        this.clear2.node.setPosition(localPos);
        this.clear2.getComponent(ParticleSystem2D).resetSystem();

        return new Promise((resolve, reject) => {
            tween(deleteNodes[0]).to(0.2, { position: center }).call(() => {

            }).start();
            tween(deleteNodes[2]).to(0.2, { position: center }).call(() => {
                // 删除节点
                deleteNodes.forEach(item => {
                    eliminateGameManager.game.deleteNodeFromeNodes(item);
                    item.destroy();
                });
                this._isEliminating = false;
                if (eliminateGameManager.game.overReason == GameOverReason.NORMAL_OVER && this.modelView.length == 0) {
                    // 消除完毕 && 堆里面没有任何的物品了
                    eliminateGameManager.uiManager.popPause();
                }

                resolve(null);
            }).start();
        });


    }

    public btnEvents(event: any, data: string) {
        switch (data) {
            case "auto":
                // 自动消除
                this._autoEliminate();
                break;
            case "delete":
                this._deleteFromSlots();
                break;
            case "shuffle":
                this._shuffle3dObjs();
                break;
            case "freeze":
                this._freeze3dObjs();
                break;
            case "pause":
                eliminateGameManager.uiManager.popPause();
                break;
        }
    }

    // 自动消除,如果槽子里面有物体的话从槽子里面取出最后一个元素，知道它的类型，然后再从堆里面找出形同的物体凑够消除数量
    private _autoEliminate() {
        let autoNodes = [];
        if (this.modelView.length == 0) {
            autoNodes = eliminateGameManager.game.getRandomThreeCommonTypeToy();
        } else {
            autoNodes = eliminateGameManager.game.getRandomThreeCommonTypeToy(this.modelView[this.modelView.length - 1]['tag']);
        }
        for (let item of autoNodes) {
            this.eliminateCheck(item);
        }
    }

    /**
     * 从槽子里面剔除元素
     */
    private _deleteFromSlots() {
        const popNode = this.modelView.pop();
        if (!popNode) return;

        let rb = popNode.getComponent(RigidBody);
        const curScale = popNode.scale.clone().multiplyScalar(1 / this._scale);
        // popNode.setScale(curScale);

        const collider = popNode.getComponent(Collider);
        collider.enabled = true;
        rb.enabled = true;
        rb.useGravity = true;

        const minX = eliminateGameManager.game.minX;
        const maxX = eliminateGameManager.game.maxX;

        const minZ = eliminateGameManager.game.minZ;
        const maxZ = eliminateGameManager.game.maxZ;

        const x = createRandom(minX + 100, maxX - 100);
        const z = createRandom(minZ - 100, maxZ + 100);

        tween(popNode).to(0.2, { position: v3(x, 300, z), scale: curScale }).call(() => {

        }).start();
    }

    /**
     * 从世界坐标的原点开始找到一个从原点指向物体坐标的向量，这个向量的法向量就是力的方向，扭矩随机
     */
    private _shuffle3dObjs() {
        const d3AllNodes = eliminateGameManager.game.getNodes();
        let len = d3AllNodes.length;
        const winPart = this.windPart.getComponent(ParticleSystem2D);

        const center = (v3(createRandom(-200, 200), 0, -createRandom(-100, 100)));
        eliminateGameManager.uiManager.camera.camera.update();

        let centerUIPos = eliminateGameManager.uiManager.camera.worldToScreen(center);
        console.log("centerUIPos is ", centerUIPos);

        const viewSize = view.getVisibleSize();
        const wratio = view.getVisibleSizeInPixel().width / view.getDesignResolutionSize().width;
        centerUIPos.subtract(v3(viewSize.width / 2, viewSize.height / 2, 0));

        winPart.node.setPosition(centerUIPos);
        winPart.resetSystem();

        for (let i = 0; i < len; i++) {
            const node = d3AllNodes[i];
            if (node['clear']) continue;
            if (!node) continue;

            let pos = node.getPosition();
            const dir = v3(pos.x, 0, pos.z).subtract(center).normalize();

            const xNoise = createRandom(5000, 10000);
            const zNoise = createRandom(5000, 10000);

            // 0的时候顺时针 1逆时针
            const rotate = createRandom(0, 2) == 0 ? -1 : 1;

            const dirNormal = v3(dir.z * rotate, 0, dir.x * rotate).multiply(v3(xNoise * clamp(Math.cos(xNoise), 0, 1), 0, zNoise * clamp(Math.cos(zNoise), 0, 1)));
            const force = v3(dirNormal.x, 200, dirNormal.z);

            const rbItem = node.getComponent(RigidBody);
            rbItem.applyImpulse(force);
            rbItem.applyTorque(force);
        }

    }

    private _freeze3dObjs() {
        const icePart = this.icePart.getComponent(ParticleSystem2D);
        icePart.resetSystem();

        eliminateGameManager.uiManager.topUI.stopTime();
    }

    update(deltaTime: number) {

    }
}

